using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

namespace RedPoint
{
    public class RedPointManager
    {
        static RedPointManager instance;
        public static RedPointManager Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new RedPointManager();
                }
                return instance;
            }
        }

        Dictionary<string, Node> nodeDic = new();
        bool isInit = false;

        public void Init(List<NodeLine> lines)
        {
            if (isInit)
            {
                Debug.LogError("RedPointManager cannot Init Twice");
                return;
            }
            foreach (var item in lines)
            {
                AddNode(item.NodeName, item.ParentName);
            }
            BuildTree();
            isInit = true;
        }
        public void AddListener(string key, Action<int> action)
        {
            if (nodeDic.TryGetValue(key, out Node node))
            {
                node.OnChangeEvent += action;
            }
        }
        public void RemoveListener(string key, Action<int> action)
        {
            if (nodeDic.TryGetValue(key, out Node node))
            {
                node.OnChangeEvent -= action;
            }
        }
        public int GetCount(string key)
        {
            if (nodeDic.TryGetValue(key, out Node node))
            {
                return node.GetCount();
            }
            else
            {
                return 0;
            }
        }
        public void SetCount(string key, int bount)
        {
            if (nodeDic.TryGetValue(key, out Node node))
            {
                if (node.ChildCount == 0)
                {
                    node.SetCount(bount);
                }
            }
        }
        public string Print()
        {
            StringBuilder sb = new StringBuilder();
            MakeStr(nodeDic["ROOT"], "");
            void MakeStr(Node node, string intent)
            {
                var str = sb.ToString();
                sb.Append($"├─ {node.NodeName}:{node.GetCount()}\n");
                node.GetString(sb, intent, MakeStr);
            }
            return "RedPointTree:\n" + sb.ToString();
        }
        void AddNode(string nodeName, string parentNodeName = "")
        {
            if (!nodeDic.TryGetValue(nodeName, out Node node))
            {
                node = new Node(nodeName);
                nodeDic.Add(nodeName, node);
            }
            if (!string.IsNullOrEmpty(parentNodeName))
            {

                if (nodeDic.TryGetValue(parentNodeName, out Node parent))
                {
                    // 检查是否会形成环路
                    if (IsDescendant(node, parent))
                    {
                        throw new Exception($"Please Fix!!!! Adding {nodeName} as a child of {parentNodeName} would create a loop. ");
                    }
                }
                else
                {
                    parent = new Node(parentNodeName);
                    nodeDic.Add(parentNodeName, parent);
                }
                parent.AddChild(node);

            }
        }
        Node BuildTree()
        {
            if (!nodeDic.TryGetValue("ROOT", out Node rootNode))
            {
                rootNode = new Node("ROOT");
                nodeDic["ROOT"] = rootNode;
            }
            foreach (var item in nodeDic)
            {
                if (item.Value.Parents.Count == 0 && item.Value.NodeName != "ROOT")
                {
                    rootNode.AddChild(item.Value);
                }
            }
            return rootNode;
        }
        // 递归检查是否为后代节点
        private bool IsDescendant(Node child, Node potentialAncestor)
        {
            foreach (var grandChild in child.Childs)
            {
                if (grandChild == potentialAncestor || IsDescendant(grandChild, potentialAncestor))
                {
                    return true;
                }
            }
            return false;
        }

    }
}